{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "2dc7db07-39d2-4da6-9812-051ff800021f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T01:45:47.940751Z",
     "iopub.status.busy": "2024-10-01T01:45:47.940130Z",
     "iopub.status.idle": "2024-10-01T01:45:47.949615Z",
     "shell.execute_reply": "2024-10-01T01:45:47.947576Z",
     "shell.execute_reply.started": "2024-10-01T01:45:47.940697Z"
    }
   },
   "outputs": [],
   "source": [
    "import json\n",
    "from IPython.display import Image\n",
    "from pydantic import BaseModel\n",
    "from langchain_core.output_parsers import PydanticOutputParser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "1fcd7bcb-2bca-4163-893a-bd8bc76188fc",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T01:45:48.862547Z",
     "iopub.status.busy": "2024-10-01T01:45:48.861981Z",
     "iopub.status.idle": "2024-10-01T01:45:48.883152Z",
     "shell.execute_reply": "2024-10-01T01:45:48.881092Z",
     "shell.execute_reply.started": "2024-10-01T01:45:48.862495Z"
    }
   },
   "outputs": [],
   "source": [
    "from dotenv import load_dotenv\n",
    "assert load_dotenv()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0315d2fd-68e7-446f-bfc4-49fa08dfa87d",
   "metadata": {},
   "source": [
    "### official "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "4a661169-c6a5-4da2-8526-be535cc8ecfb",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T01:37:02.946892Z",
     "iopub.status.busy": "2024-10-01T01:37:02.946591Z",
     "iopub.status.idle": "2024-10-01T01:37:02.959028Z",
     "shell.execute_reply": "2024-10-01T01:37:02.957083Z",
     "shell.execute_reply.started": "2024-10-01T01:37:02.946864Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<img src=\"https://wangwei1237.github.io/2023/09/20/Introduction-to-LangChain/langchain.png\" width=\"500\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Image(url='https://wangwei1237.github.io/2023/09/20/Introduction-to-LangChain/langchain.png', width=500)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c659d669-49d5-4590-971e-c914a2537e85",
   "metadata": {},
   "source": [
    "- https://github.com/hwchase17/langchain-0.1-guides/blob/master/output_parsers.ipynb\n",
    "- lcel => agent\n",
    "    - variable assignment \n",
    "    - prompt template\n",
    "    - llm (with tools)\n",
    "    - output parse"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "1800bfe1-a9d3-40aa-b3a3-eee6862716ec",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-12-30T14:36:02.320423Z",
     "iopub.status.busy": "2024-12-30T14:36:02.320120Z",
     "iopub.status.idle": "2024-12-30T14:36:02.328030Z",
     "shell.execute_reply": "2024-12-30T14:36:02.326124Z",
     "shell.execute_reply.started": "2024-12-30T14:36:02.320401Z"
    }
   },
   "outputs": [],
   "source": [
    "from langchain.output_parsers import PydanticOutputParser\n",
    "from pydantic import BaseModel, Field\n",
    "from typing import List"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "e7b7a6a4-5211-468f-9eb3-a107f3381767",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-12-30T14:36:04.414829Z",
     "iopub.status.busy": "2024-12-30T14:36:04.414249Z",
     "iopub.status.idle": "2024-12-30T14:36:04.431904Z",
     "shell.execute_reply": "2024-12-30T14:36:04.429874Z",
     "shell.execute_reply.started": "2024-12-30T14:36:04.414778Z"
    }
   },
   "outputs": [],
   "source": [
    "class Ingredient(BaseModel):\n",
    "    name: str = Field(description=\"The name of the ingredient\")\n",
    "    quantity: str = Field(description=\"The specific unit of measurement corresponding to the quantity, such as grams, ounces, liters, etc.\")\n",
    "    unit: str = Field(description=\"The amount of the ingredient required for the recipe. This can be represented using various units such as grams, cups, teaspoons, etc.\")\n",
    "\n",
    "class Recipe(BaseModel):\n",
    "    name: str = Field(description=\"The name of the recipe\")\n",
    "    ingredients: List[Ingredient] = Field(description=\"The list of ingredients for the recipe\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "d080b660-0198-4ce2-b311-14521a97e03e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-12-30T14:36:12.639778Z",
     "iopub.status.busy": "2024-12-30T14:36:12.639179Z",
     "iopub.status.idle": "2024-12-30T14:36:12.648356Z",
     "shell.execute_reply": "2024-12-30T14:36:12.646682Z",
     "shell.execute_reply.started": "2024-12-30T14:36:12.639729Z"
    }
   },
   "outputs": [],
   "source": [
    "parser = PydanticOutputParser(pydantic_object=Recipe)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "651d4d59-3960-4776-aa0a-de814a2cce87",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-12-30T14:36:49.788522Z",
     "iopub.status.busy": "2024-12-30T14:36:49.787949Z",
     "iopub.status.idle": "2024-12-30T14:36:49.798623Z",
     "shell.execute_reply": "2024-12-30T14:36:49.797169Z",
     "shell.execute_reply.started": "2024-12-30T14:36:49.788474Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The output should be formatted as a JSON instance that conforms to the JSON schema below.\n",
      "\n",
      "As an example, for the schema {\"properties\": {\"foo\": {\"title\": \"Foo\", \"description\": \"a list of strings\", \"type\": \"array\", \"items\": {\"type\": \"string\"}}}, \"required\": [\"foo\"]}\n",
      "the object {\"foo\": [\"bar\", \"baz\"]} is a well-formatted instance of the schema. The object {\"properties\": {\"foo\": [\"bar\", \"baz\"]}} is not well-formatted.\n",
      "\n",
      "Here is the output schema:\n",
      "```\n",
      "{\"$defs\": {\"Ingredient\": {\"properties\": {\"name\": {\"description\": \"The name of the ingredient\", \"title\": \"Name\", \"type\": \"string\"}, \"quantity\": {\"description\": \"The specific unit of measurement corresponding to the quantity, such as grams, ounces, liters, etc.\", \"title\": \"Quantity\", \"type\": \"string\"}, \"unit\": {\"description\": \"The amount of the ingredient required for the recipe. This can be represented using various units such as grams, cups, teaspoons, etc.\", \"title\": \"Unit\", \"type\": \"string\"}}, \"required\": [\"name\", \"quantity\", \"unit\"], \"title\": \"Ingredient\", \"type\": \"object\"}}, \"properties\": {\"name\": {\"description\": \"The name of the recipe\", \"title\": \"Name\", \"type\": \"string\"}, \"ingredients\": {\"description\": \"The list of ingredients for the recipe\", \"items\": {\"$ref\": \"#/$defs/Ingredient\"}, \"title\": \"Ingredients\", \"type\": \"array\"}}, \"required\": [\"name\", \"ingredients\"]}\n",
      "```\n"
     ]
    }
   ],
   "source": [
    "from rich.pretty import pprint\n",
    "print(parser.get_format_instructions())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e988ae2-4b79-46aa-899c-deb692ec1ef8",
   "metadata": {},
   "source": [
    "#### converting messages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "8bbc3b37-20ba-49f0-ab78-aeffa1f4bb6b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T02:25:03.171961Z",
     "iopub.status.busy": "2024-10-01T02:25:03.171560Z",
     "iopub.status.idle": "2024-10-01T02:25:03.178818Z",
     "shell.execute_reply": "2024-10-01T02:25:03.177172Z",
     "shell.execute_reply.started": "2024-10-01T02:25:03.171926Z"
    }
   },
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_core.prompts import ChatPromptTemplate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "8c61debc-030b-4898-8e7d-48e5afd6349c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T02:25:04.181204Z",
     "iopub.status.busy": "2024-10-01T02:25:04.180645Z",
     "iopub.status.idle": "2024-10-01T02:25:04.284064Z",
     "shell.execute_reply": "2024-10-01T02:25:04.282455Z",
     "shell.execute_reply.started": "2024-10-01T02:25:04.181154Z"
    }
   },
   "outputs": [],
   "source": [
    "prompt = ChatPromptTemplate.from_template(\"Tell me a joke about {topic}\")\n",
    "model = ChatOpenAI(model='gpt-3.5-turbo')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "3e5d96c6-a0e2-48d4-b2d2-a20e83aafe81",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T02:25:05.232732Z",
     "iopub.status.busy": "2024-10-01T02:25:05.232374Z",
     "iopub.status.idle": "2024-10-01T02:25:05.239801Z",
     "shell.execute_reply": "2024-10-01T02:25:05.238144Z",
     "shell.execute_reply.started": "2024-10-01T02:25:05.232701Z"
    }
   },
   "outputs": [],
   "source": [
    "chain = prompt | model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "4127ab13-3092-4ba2-ac80-65ed2222f112",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T02:25:06.190132Z",
     "iopub.status.busy": "2024-10-01T02:25:06.189580Z",
     "iopub.status.idle": "2024-10-01T02:25:07.222592Z",
     "shell.execute_reply": "2024-10-01T02:25:07.220446Z",
     "shell.execute_reply.started": "2024-10-01T02:25:06.190082Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='Why did the pig go to the casino? To play the slop machines!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 16, 'prompt_tokens': 13, 'total_tokens': 29, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-dbb76cac-dc4e-4f72-8f2f-416cc8192a24-0', usage_metadata={'input_tokens': 13, 'output_tokens': 16, 'total_tokens': 29})"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.invoke({'topic': 'pig'})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "2888ea2e-eefb-4f4c-8be8-97f725093fa8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T02:25:08.445997Z",
     "iopub.status.busy": "2024-10-01T02:25:08.445437Z",
     "iopub.status.idle": "2024-10-01T02:25:08.453615Z",
     "shell.execute_reply": "2024-10-01T02:25:08.451822Z",
     "shell.execute_reply.started": "2024-10-01T02:25:08.445947Z"
    }
   },
   "outputs": [],
   "source": [
    "from langchain_core.output_parsers import StrOutputParser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "f2572652-b47a-4762-9927-06273dd974f8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T02:25:09.988808Z",
     "iopub.status.busy": "2024-10-01T02:25:09.988254Z",
     "iopub.status.idle": "2024-10-01T02:25:09.996181Z",
     "shell.execute_reply": "2024-10-01T02:25:09.994602Z",
     "shell.execute_reply.started": "2024-10-01T02:25:09.988758Z"
    }
   },
   "outputs": [],
   "source": [
    "parser = StrOutputParser()\n",
    "chain |= parser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "08e9782e-f8cd-4251-ae78-18803d299a58",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T02:25:11.681586Z",
     "iopub.status.busy": "2024-10-01T02:25:11.681006Z",
     "iopub.status.idle": "2024-10-01T02:25:12.696513Z",
     "shell.execute_reply": "2024-10-01T02:25:12.694548Z",
     "shell.execute_reply.started": "2024-10-01T02:25:11.681536Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Why did the pig go to the casino? Because he heard they had a lot of \"squeal\" machines!'"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.invoke({'topic': 'pig'})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "bf49cde6-2bbe-479e-a459-6113a3cb4a83",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T01:46:29.674967Z",
     "iopub.status.busy": "2024-10-01T01:46:29.674218Z",
     "iopub.status.idle": "2024-10-01T01:46:29.686130Z",
     "shell.execute_reply": "2024-10-01T01:46:29.684204Z",
     "shell.execute_reply.started": "2024-10-01T01:46:29.674911Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptTemplate(input_variables=['topic'], input_types={}, partial_variables={}, messages=[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['topic'], input_types={}, partial_variables={}, template='Tell me a joke about {topic}'), additional_kwargs={})])\n",
       "| ChatOpenAI(client=<openai.resources.chat.completions.Completions object at 0x7ebb83b6a0f0>, async_client=<openai.resources.chat.completions.AsyncCompletions object at 0x7ebb83b6bf50>, root_client=<openai.OpenAI object at 0x7ebb83b29f40>, root_async_client=<openai.AsyncOpenAI object at 0x7ebb83b6a120>, model_kwargs={}, openai_api_key=SecretStr('**********'))\n",
       "| StrOutputParser()"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "0db7d0ca-0abf-4e8f-8800-a7a2964a832f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T02:25:15.333612Z",
     "iopub.status.busy": "2024-10-01T02:25:15.333036Z",
     "iopub.status.idle": "2024-10-01T02:25:16.178259Z",
     "shell.execute_reply": "2024-10-01T02:25:16.176481Z",
     "shell.execute_reply.started": "2024-10-01T02:25:15.333563Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Why did the pig go to the casino? \\nTo play the slop machine!'"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain = prompt | model | parser\n",
    "chain.invoke({'topic': 'pig'})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "867ec16d-b9ee-4c27-9afa-d49d45038388",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T02:25:17.399612Z",
     "iopub.status.busy": "2024-10-01T02:25:17.399042Z",
     "iopub.status.idle": "2024-10-01T02:25:18.125119Z",
     "shell.execute_reply": "2024-10-01T02:25:18.123304Z",
     "shell.execute_reply.started": "2024-10-01T02:25:17.399561Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"Why did the apple go to the doctor?\\nBecause it wasn't peeling well!\""
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain = {'topic': lambda x: x['input']} | prompt | model | parser\n",
    "chain.invoke({'input': 'apple'})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "244ec6ba-da18-486e-b777-86aa965afdd3",
   "metadata": {},
   "source": [
    "#### OpenAI Function Calling"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "98256b06-832b-4809-80e8-20874b7fdea8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T01:47:07.146264Z",
     "iopub.status.busy": "2024-10-01T01:47:07.145648Z",
     "iopub.status.idle": "2024-10-01T01:47:07.155740Z",
     "shell.execute_reply": "2024-10-01T01:47:07.153661Z",
     "shell.execute_reply.started": "2024-10-01T01:47:07.146198Z"
    }
   },
   "outputs": [],
   "source": [
    "from langchain_core.utils.function_calling import convert_to_openai_function\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from pydantic import BaseModel, Field, validator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "4098d48b-4782-4814-9e31-cd44bc74aa6c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T01:47:08.199315Z",
     "iopub.status.busy": "2024-10-01T01:47:08.198751Z",
     "iopub.status.idle": "2024-10-01T01:47:08.348000Z",
     "shell.execute_reply": "2024-10-01T01:47:08.346475Z",
     "shell.execute_reply.started": "2024-10-01T01:47:08.199266Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'name': 'Joke',\n",
       "  'description': 'Joke to tell user.',\n",
       "  'parameters': {'properties': {'setup': {'description': 'question to set up a joke',\n",
       "     'type': 'string'},\n",
       "    'punchline': {'description': 'answer to resolve the joke',\n",
       "     'type': 'string'}},\n",
       "   'required': ['setup', 'punchline'],\n",
       "   'type': 'object'}}]"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class Joke(BaseModel):\n",
    "    \"\"\"Joke to tell user.\"\"\"\n",
    "\n",
    "    setup: str = Field(description=\"question to set up a joke\")\n",
    "    punchline: str = Field(description=\"answer to resolve the joke\")\n",
    "\n",
    "openai_functions = [convert_to_openai_function(Joke)]\n",
    "openai_functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "559a393d-baf4-4c6e-80b9-5a0247bfd24d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T01:47:09.935962Z",
     "iopub.status.busy": "2024-10-01T01:47:09.935642Z",
     "iopub.status.idle": "2024-10-01T01:47:10.054462Z",
     "shell.execute_reply": "2024-10-01T01:47:10.053018Z",
     "shell.execute_reply.started": "2024-10-01T01:47:09.935934Z"
    }
   },
   "outputs": [],
   "source": [
    "from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "dfaf0d49-90ed-45d4-ab70-f7aca32ef18a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T01:47:12.037049Z",
     "iopub.status.busy": "2024-10-01T01:47:12.036728Z",
     "iopub.status.idle": "2024-10-01T01:47:12.043947Z",
     "shell.execute_reply": "2024-10-01T01:47:12.042342Z",
     "shell.execute_reply.started": "2024-10-01T01:47:12.037022Z"
    }
   },
   "outputs": [],
   "source": [
    "parser = JsonOutputFunctionsParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "7145a0b1-32cc-44fa-8837-b622d8964f54",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T01:47:14.162803Z",
     "iopub.status.busy": "2024-10-01T01:47:14.162251Z",
     "iopub.status.idle": "2024-10-01T01:47:14.170888Z",
     "shell.execute_reply": "2024-10-01T01:47:14.169022Z",
     "shell.execute_reply.started": "2024-10-01T01:47:14.162752Z"
    }
   },
   "outputs": [],
   "source": [
    "chain = prompt | model.bind(functions=openai_functions) | parser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "7c8b6fe1-1fa9-463f-a7fe-e7ba92b00bff",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-10-01T01:47:15.434761Z",
     "iopub.status.busy": "2024-10-01T01:47:15.434175Z",
     "iopub.status.idle": "2024-10-01T01:47:16.692332Z",
     "shell.execute_reply": "2024-10-01T01:47:16.690470Z",
     "shell.execute_reply.started": "2024-10-01T01:47:15.434712Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'setup': 'Why did the pig go to the casino?',\n",
       " 'punchline': 'To play the slop machine!'}"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.invoke({'topic': 'pig'})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3b3e69a1-8794-4834-a38e-72bee4a5b461",
   "metadata": {},
   "source": [
    "### PydanticOutputParser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "7bde2d97-5c83-4db7-83ce-9005c4749200",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T15:57:49.034408Z",
     "iopub.status.busy": "2024-09-23T15:57:49.033836Z",
     "iopub.status.idle": "2024-09-23T15:57:49.043169Z",
     "shell.execute_reply": "2024-09-23T15:57:49.041524Z",
     "shell.execute_reply.started": "2024-09-23T15:57:49.034358Z"
    }
   },
   "outputs": [],
   "source": [
    "class WritingScore(BaseModel):\n",
    "    readability: int\n",
    "    conciseness: int"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "943ff35e-5d61-4ec0-802b-91b68503aa5c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T15:57:49.045549Z",
     "iopub.status.busy": "2024-09-23T15:57:49.045025Z",
     "iopub.status.idle": "2024-09-23T15:57:49.068530Z",
     "shell.execute_reply": "2024-09-23T15:57:49.066700Z",
     "shell.execute_reply.started": "2024-09-23T15:57:49.045501Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'title': 'WritingScore',\n",
       " 'type': 'object',\n",
       " 'properties': {'readability': {'title': 'Readability', 'type': 'integer'},\n",
       "  'conciseness': {'title': 'Conciseness', 'type': 'integer'}},\n",
       " 'required': ['readability', 'conciseness']}"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "schema = WritingScore.schema()\n",
    "schema"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "f9bd5b38-2cb9-4ae2-82e0-ae3c98c92b0b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T15:57:49.070700Z",
     "iopub.status.busy": "2024-09-23T15:57:49.070173Z",
     "iopub.status.idle": "2024-09-23T15:57:49.077928Z",
     "shell.execute_reply": "2024-09-23T15:57:49.076297Z",
     "shell.execute_reply.started": "2024-09-23T15:57:49.070653Z"
    }
   },
   "outputs": [],
   "source": [
    "resp = \"\"\"```\n",
    "{\n",
    "  \"readability\": 8,\n",
    "  \"conciseness\": 9\n",
    "}\n",
    "```\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "a9c9ec8c-7978-492c-be40-e211b21a632f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T15:57:49.079914Z",
     "iopub.status.busy": "2024-09-23T15:57:49.079417Z",
     "iopub.status.idle": "2024-09-23T15:57:49.090437Z",
     "shell.execute_reply": "2024-09-23T15:57:49.088521Z",
     "shell.execute_reply.started": "2024-09-23T15:57:49.079868Z"
    }
   },
   "outputs": [],
   "source": [
    "parser = PydanticOutputParser(pydantic_object=WritingScore)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "5a7cab47-fd3a-4c07-bed8-63ae896a460f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T15:57:49.092720Z",
     "iopub.status.busy": "2024-09-23T15:57:49.092197Z",
     "iopub.status.idle": "2024-09-23T15:57:49.106832Z",
     "shell.execute_reply": "2024-09-23T15:57:49.104878Z",
     "shell.execute_reply.started": "2024-09-23T15:57:49.092673Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "WritingScore(readability=8, conciseness=9)"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "parser.parse(resp)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f4ab943-9829-464f-b44d-572a4b914f05",
   "metadata": {},
   "source": [
    "### json output"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dec50557-7958-4470-b0ec-01c24810399f",
   "metadata": {},
   "source": [
    "- https://python.langchain.com/docs/integrations/chat/openai/#stricttrue"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "02576ad0-ecdb-4c10-a747-074e1f200c8f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T15:58:38.440600Z",
     "iopub.status.busy": "2024-09-23T15:58:38.440298Z",
     "iopub.status.idle": "2024-09-23T15:58:40.042482Z",
     "shell.execute_reply": "2024-09-23T15:58:40.041273Z",
     "shell.execute_reply.started": "2024-09-23T15:58:38.440575Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='Hello! How can I assist you today?', response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 8, 'total_tokens': 17, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_3537616b13', 'finish_reason': 'stop', 'logprobs': None}, id='run-52462bb3-54fd-47e9-a7db-5bd10b8e94a6-0', usage_metadata={'input_tokens': 8, 'output_tokens': 9, 'total_tokens': 17})"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model = ChatOpenAI(model='gpt-4o')\n",
    "model.invoke('hi')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "9e47dc60-6b8c-4b5c-a4b2-d69c716e4ded",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T15:58:41.748199Z",
     "iopub.status.busy": "2024-09-23T15:58:41.747593Z",
     "iopub.status.idle": "2024-09-23T15:58:41.773706Z",
     "shell.execute_reply": "2024-09-23T15:58:41.771876Z",
     "shell.execute_reply.started": "2024-09-23T15:58:41.748147Z"
    }
   },
   "outputs": [],
   "source": [
    "from langchain_core.tools import tool\n",
    "\n",
    "@tool\n",
    "def add(a: int, b: int) -> int:\n",
    "    \"\"\"Adds a and b.\n",
    "    \n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a + b\n",
    "\n",
    "@tool\n",
    "def multiply(a: int, b: int) -> int:\n",
    "    \"\"\"Multiplies a and b.\n",
    "    \n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a * b\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "1775b1c1-f72c-42f9-8aec-eb0567dfa10a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T16:02:42.350457Z",
     "iopub.status.busy": "2024-09-23T16:02:42.349927Z",
     "iopub.status.idle": "2024-09-23T16:02:44.133367Z",
     "shell.execute_reply": "2024-09-23T16:02:44.132058Z",
     "shell.execute_reply.started": "2024-09-23T16:02:42.350412Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Q3ZHvvKR7uTC8pJe61sBu1vP', 'function': {'arguments': '{\"a\": 3, \"b\": 12}', 'name': 'multiply'}, 'type': 'function'}, {'id': 'call_UgcQTCjmQcfKr0i2uwHNgr7k', 'function': {'arguments': '{\"a\": 11, \"b\": 49}', 'name': 'add'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 50, 'prompt_tokens': 111, 'total_tokens': 161, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_e375328146', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-95c85515-6075-47e1-ba8c-f2ff98748837-0', tool_calls=[{'name': 'multiply', 'args': {'a': 3, 'b': 12}, 'id': 'call_Q3ZHvvKR7uTC8pJe61sBu1vP', 'type': 'tool_call'}, {'name': 'add', 'args': {'a': 11, 'b': 49}, 'id': 'call_UgcQTCjmQcfKr0i2uwHNgr7k', 'type': 'tool_call'}], usage_metadata={'input_tokens': 111, 'output_tokens': 50, 'total_tokens': 161})"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.messages import HumanMessage\n",
    "# llm_with_tools = model.bind_tools([add, multiply], strict=True)\n",
    "llm_with_tools = model.bind_tools([add, multiply], )\n",
    "messages = [HumanMessage('what is 3*12? Also, what is 11+49?')]\n",
    "ai_msg = llm_with_tools.invoke(messages)\n",
    "messages.append(ai_msg)\n",
    "ai_msg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "e42d83cf-e0a9-4e27-b70b-7cf159998cd8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T16:03:28.239015Z",
     "iopub.status.busy": "2024-09-23T16:03:28.238606Z",
     "iopub.status.idle": "2024-09-23T16:03:28.248152Z",
     "shell.execute_reply": "2024-09-23T16:03:28.246930Z",
     "shell.execute_reply.started": "2024-09-23T16:03:28.238977Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'name': 'multiply',\n",
       "  'args': {'a': 3, 'b': 12},\n",
       "  'id': 'call_Q3ZHvvKR7uTC8pJe61sBu1vP',\n",
       "  'type': 'tool_call'},\n",
       " {'name': 'add',\n",
       "  'args': {'a': 11, 'b': 49},\n",
       "  'id': 'call_UgcQTCjmQcfKr0i2uwHNgr7k',\n",
       "  'type': 'tool_call'}]"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ai_msg.tool_calls"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "f187b5b9-9719-4fce-995b-7f5ed4fba7dc",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T16:04:36.780199Z",
     "iopub.status.busy": "2024-09-23T16:04:36.779600Z",
     "iopub.status.idle": "2024-09-23T16:04:36.791705Z",
     "shell.execute_reply": "2024-09-23T16:04:36.789699Z",
     "shell.execute_reply.started": "2024-09-23T16:04:36.780147Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'a': 3, 'b': 12}"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ai_msg.tool_calls[0]['args']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "ab5f0cbb-f1a3-4221-a3d4-f6c97df8d5db",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T16:04:48.718802Z",
     "iopub.status.busy": "2024-09-23T16:04:48.718178Z",
     "iopub.status.idle": "2024-09-23T16:04:48.734646Z",
     "shell.execute_reply": "2024-09-23T16:04:48.732681Z",
     "shell.execute_reply.started": "2024-09-23T16:04:48.718749Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "36"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "multiply.invoke(ai_msg.tool_calls[0]['args'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1dd24698-7965-4800-a63a-70d1ffb72dbc",
   "metadata": {},
   "source": [
    "### example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "81acf6a0-be06-4055-bf22-0f59a6ac64c4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T16:08:24.044942Z",
     "iopub.status.busy": "2024-09-23T16:08:24.044363Z",
     "iopub.status.idle": "2024-09-23T16:08:24.052681Z",
     "shell.execute_reply": "2024-09-23T16:08:24.050880Z",
     "shell.execute_reply.started": "2024-09-23T16:08:24.044886Z"
    }
   },
   "outputs": [],
   "source": [
    "from pydantic import BaseModel"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "f41d8691-3666-4a13-aceb-799dd81fc010",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T16:09:16.865358Z",
     "iopub.status.busy": "2024-09-23T16:09:16.864734Z",
     "iopub.status.idle": "2024-09-23T16:09:16.880439Z",
     "shell.execute_reply": "2024-09-23T16:09:16.878644Z",
     "shell.execute_reply.started": "2024-09-23T16:09:16.865303Z"
    }
   },
   "outputs": [],
   "source": [
    "class Step(BaseModel):\n",
    "    explanation: str\n",
    "    output: str\n",
    "class MathResp(BaseModel):\n",
    "    steps: list[Step]\n",
    "    final_answer: str"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "92cb2d38-16e8-4aca-9293-a58150a960dd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T16:10:39.619877Z",
     "iopub.status.busy": "2024-09-23T16:10:39.619367Z",
     "iopub.status.idle": "2024-09-23T16:10:41.953940Z",
     "shell.execute_reply": "2024-09-23T16:10:41.952050Z",
     "shell.execute_reply.started": "2024-09-23T16:10:39.619834Z"
    }
   },
   "outputs": [],
   "source": [
    "tools = [MathResp]\n",
    "llm = ChatOpenAI(model='gpt-4o')\n",
    "math_tutor = llm.bind_tools(tools)\n",
    "\n",
    "as_msg = math_tutor.invoke('solve 8x+31=2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "00797fcf-5030-48cf-95be-a761081ac74b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T16:10:43.274576Z",
     "iopub.status.busy": "2024-09-23T16:10:43.273983Z",
     "iopub.status.idle": "2024-09-23T16:10:43.286192Z",
     "shell.execute_reply": "2024-09-23T16:10:43.284176Z",
     "shell.execute_reply.started": "2024-09-23T16:10:43.274523Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_i2aCQLtmp96fSp1ecfc6MJLF', 'function': {'arguments': '{\"steps\":[{\"explanation\":\"Subtract 31 from both sides of the equation to isolate the term with the variable.\",\"output\":\"8x + 31 - 31 = 2 - 31\"},{\"explanation\":\"Simplify both sides of the equation.\",\"output\":\"8x = -29\"},{\"explanation\":\"Divide both sides of the equation by 8 to solve for x.\",\"output\":\"8x / 8 = -29 / 8\"},{\"explanation\":\"Simplify the right side of the equation.\",\"output\":\"x = -29/8\"}],\"final_answer\":\"x = -29/8\"}', 'name': 'MathResp'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 132, 'prompt_tokens': 58, 'total_tokens': 190, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_e375328146', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-bd1cd2e1-ab65-49da-8f0b-0caf665f830e-0', tool_calls=[{'name': 'MathResp', 'args': {'steps': [{'explanation': 'Subtract 31 from both sides of the equation to isolate the term with the variable.', 'output': '8x + 31 - 31 = 2 - 31'}, {'explanation': 'Simplify both sides of the equation.', 'output': '8x = -29'}, {'explanation': 'Divide both sides of the equation by 8 to solve for x.', 'output': '8x / 8 = -29 / 8'}, {'explanation': 'Simplify the right side of the equation.', 'output': 'x = -29/8'}], 'final_answer': 'x = -29/8'}, 'id': 'call_i2aCQLtmp96fSp1ecfc6MJLF', 'type': 'tool_call'}], usage_metadata={'input_tokens': 58, 'output_tokens': 132, 'total_tokens': 190})"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "as_msg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "b488aa02-ff3a-4beb-9fdb-713dff7ccbee",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T16:10:51.072206Z",
     "iopub.status.busy": "2024-09-23T16:10:51.071639Z",
     "iopub.status.idle": "2024-09-23T16:10:51.084851Z",
     "shell.execute_reply": "2024-09-23T16:10:51.083041Z",
     "shell.execute_reply.started": "2024-09-23T16:10:51.072154Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'name': 'MathResp',\n",
       "  'args': {'steps': [{'explanation': 'Subtract 31 from both sides of the equation to isolate the term with the variable.',\n",
       "     'output': '8x + 31 - 31 = 2 - 31'},\n",
       "    {'explanation': 'Simplify both sides of the equation.',\n",
       "     'output': '8x = -29'},\n",
       "    {'explanation': 'Divide both sides of the equation by 8 to solve for x.',\n",
       "     'output': '8x / 8 = -29 / 8'},\n",
       "    {'explanation': 'Simplify the right side of the equation.',\n",
       "     'output': 'x = -29/8'}],\n",
       "   'final_answer': 'x = -29/8'},\n",
       "  'id': 'call_i2aCQLtmp96fSp1ecfc6MJLF',\n",
       "  'type': 'tool_call'}]"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "as_msg.tool_calls"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "6e3b64d3-3331-4d71-8a33-62a4b5dd6bee",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T16:11:12.419058Z",
     "iopub.status.busy": "2024-09-23T16:11:12.418454Z",
     "iopub.status.idle": "2024-09-23T16:11:12.431310Z",
     "shell.execute_reply": "2024-09-23T16:11:12.429447Z",
     "shell.execute_reply.started": "2024-09-23T16:11:12.419006Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'steps': [{'explanation': 'Subtract 31 from both sides of the equation to isolate the term with the variable.',\n",
       "   'output': '8x + 31 - 31 = 2 - 31'},\n",
       "  {'explanation': 'Simplify both sides of the equation.',\n",
       "   'output': '8x = -29'},\n",
       "  {'explanation': 'Divide both sides of the equation by 8 to solve for x.',\n",
       "   'output': '8x / 8 = -29 / 8'},\n",
       "  {'explanation': 'Simplify the right side of the equation.',\n",
       "   'output': 'x = -29/8'}],\n",
       " 'final_answer': 'x = -29/8'}"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "as_msg.tool_calls[0]['args']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "cb661d4a-548d-4afe-b29c-6e2a274512fb",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-23T16:13:58.600079Z",
     "iopub.status.busy": "2024-09-23T16:13:58.599469Z",
     "iopub.status.idle": "2024-09-23T16:13:58.609643Z",
     "shell.execute_reply": "2024-09-23T16:13:58.607682Z",
     "shell.execute_reply.started": "2024-09-23T16:13:58.600028Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "step: 1\n",
      "explanation: Subtract 31 from both sides of the equation to isolate the term with the variable.\n",
      "output: 8x + 31 - 31 = 2 - 31\n",
      "\n",
      "step: 2\n",
      "explanation: Simplify both sides of the equation.\n",
      "output: 8x = -29\n",
      "\n",
      "step: 3\n",
      "explanation: Divide both sides of the equation by 8 to solve for x.\n",
      "output: 8x / 8 = -29 / 8\n",
      "\n",
      "step: 4\n",
      "explanation: Simplify the right side of the equation.\n",
      "output: x = -29/8\n",
      "\n",
      "final answer: x = -29/8\n"
     ]
    }
   ],
   "source": [
    "for i, step in enumerate(as_msg.tool_calls[0]['args']['steps']):\n",
    "    print(f'step: {i+1}\\nexplanation: {step['explanation']}\\noutput: {step['output']}\\n')\n",
    "print(f'final answer: {as_msg.tool_calls[0]['args']['final_answer']}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eb36ece1-4a22-443b-8585-ad5131019aff",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "agent",
   "language": "python",
   "name": "agent"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
